package swimv2gm.bl.session;

import java.util.*;

import javax.ejb.Stateless;
import javax.persistence.*;

import org.jboss.ejb3.annotation.RemoteBinding;

import swimv2gm.bl.domain.*;
import swimv2gm.bl.util.*;

/**
 * Implementazione del gestore di richieste di lavoro.
 * 
 * @author Matteo Gallesio
 */
@Stateless
@RemoteBinding(jndiBinding = "WorkRequestManager")
public class WorkRequestManagerBean implements WorkRequestManager {
	@PersistenceContext(unitName = "swimv2")
	private EntityManager manager;

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean createRequest(long mitt,long dest,long campo,String desc) {
		if (mitt == dest || !Utilities.validate(desc,Utilities.REQUIRED)) {
			return false;
		}

		InternalWorkRequest wr = new InternalWorkRequest();

		User u = manager.find(User.class,mitt);
		if (u == null)
			return false;
		u.addSentRequest(wr);
		wr.setMittente(u);

		if (!initRequest(wr,dest,campo,desc))
			return false;

		try {
			manager.persist(wr);
		} catch (PersistenceException e) {
			return false;
		}

		return true;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean createRequest(String mitt,long dest,long campo,String desc) {
		if (!Utilities.validate(desc,Utilities.REQUIRED) || !Utilities.validate(mitt,Utilities.EMAIL)) {
			return false;
		}
		ExternalWorkRequest wr = new ExternalWorkRequest();
		wr.setMittente(mitt);

		if (!initRequest(wr,dest,campo,desc))
			return false;

		try {
			manager.persist(wr);
		} catch (PersistenceException e) {
			return false;
		}

		return true;
	}

	private boolean initRequest(WorkRequest wr,long dest,long campo,String desc) {
		User u = manager.find(User.class,dest);
		if (u == null)
			return false;
		u.addReceivedRequest(wr);
		wr.setDestinatario(manager.find(User.class,dest));
		Ability a = manager.getReference(Ability.class,campo);
		if (a == null)
			return false;
		wr.setCampo(a);
		wr.setDescrizione(desc);
		wr.setStato(WorkRequestStatus.PENDING);
		wr.setTimestamp(new Date());
		return true;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean processRequest(long wrid,boolean accepted,long dest_uid) {
		WorkRequest wr = manager.find(WorkRequest.class,wrid);
		if (wr == null || wr.getStato() != WorkRequestStatus.PENDING || wr.getDestinatario().getId() != dest_uid)
			return false;

		if (accepted)
			wr.setStato(WorkRequestStatus.ACCEPTED);
		else
			wr.setStato(WorkRequestStatus.DECLINED);

		return true;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public List<WorkRequestData> getSentWorkRequestsData(long uid) {
		User u = manager.getReference(User.class,uid);
		if (u == null)
			return null;
		String qw = "select new swimv2gm.bl.util.WorkRequestData(wr.id,wr.timestamp,wr.stato,dest.uid,concat(dest.nome,' ',dest.cognome))"
				+ " from utenti mitt, in (mitt.sentRequests) wr, in (wr.destinatario) dest"
				+ " where mitt = :u"
				+ " order by wr.timestamp,dest.cognome";
		Query q = manager.createQuery(qw);

		q.setParameter("u",u);
		List<WorkRequestData> res = q.getResultList();

		return res;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	// query con nuovo formato?
	public List<WorkRequestData> getReceivedWorkRequestsData(long uid) {
		User u = manager.getReference(User.class,uid);
		if (u == null)
			return null;
		Query internal = manager
				.createQuery("select new swimv2gm.bl.util.WorkRequestData(wr.id,wr.timestamp,wr.stato,u.uid,concat(u.nome,' ',u.cognome)) from richiestelavoro wr, richiesteinterne iwr, utenti u where u=iwr.mittente and iwr.id=wr.id and wr.destinatario=:u order by wr.timestamp,u.cognome");
		Query external = manager
				.createQuery("select new swimv2gm.bl.util.WorkRequestData(wr.id,wr.timestamp,wr.stato,ewr.mittente) from richiestelavoro wr, richiesteesterne ewr where ewr.id=wr.id and wr.destinatario=:u order by wr.timestamp");
		internal.setParameter("u",u);
		external.setParameter("u",u);
		List<WorkRequestData> res = internal.getResultList();

		res.addAll(external.getResultList());

		return res;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Map<String,String> getRequestData(long wrid) {
		// potenzialmente opportuno usare solo uno tra mitt/dest
		WorkRequest wr = manager.find(WorkRequest.class,wrid);
		if (wr == null)
			return null;

		Map<String,String> res = new HashMap<String,String>();

		res.put("id",Long.toString(wr.getId()));
		res.put("desc",wr.getDescrizione());
		User dest = wr.getDestinatario();
		res.put("dest_id",Long.toString(dest.getId()));
		res.put("dest_name",dest.getNome() + " " + dest.getCognome());

		if (wr.isInternal()) {
			User mitt = ((InternalWorkRequest)wr).getMittente();
			res.put("mitt_id",Long.toString(mitt.getId()));
			res.put("mitt_name",mitt.getNome() + " " + mitt.getCognome());
		}
		else {
			res.put("mitt_name",((ExternalWorkRequest)wr).getMittente());
		}
		res.put("date",wr.getTimestamp().toString()); // formato...
		Ability a = wr.getCampo();
		res.put("a_id",Long.toString(a.getId()));
		res.put("a_name",a.getNome());
		res.put("status",wr.getStato().toString());
		return res;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public WorkRequest getWorkRequest(long wrid) {
		return manager.find(WorkRequest.class,wrid);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public InternalWorkRequest getInternalWorkRequest(long iwrid) {
		return manager.find(InternalWorkRequest.class,iwrid);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ExternalWorkRequest getExternalWorkRequest(long ewrid) {
		return manager.find(ExternalWorkRequest.class,ewrid);
	}
}
